/**
 * Class: PowerDisplay
 *
 * Purpose: 
 *
 * Created: Feb 17, 2010 @ 11:49:55 AM
 * @author Ken Scott
 */
package org.openfantasia.songanalyst.controls;

import org.openfantasia.songanalyst.SongObserver;
import org.openfantasia.ui.Layout;
import org.openfantasia.util.listener.Event;
import org.openfantasia.util.listener.Listener;
import org.openfantasia.rsrc.Resources;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.NumberFormat;
import java.util.ArrayList;

public class PlaybackControls extends JComponent implements Listener {

	public static final NumberFormat DOUBLE_FORMAT = NumberFormat.getInstance();


	static {
		DOUBLE_FORMAT.setMinimumFractionDigits(3);
		DOUBLE_FORMAT.setMaximumFractionDigits(3);
	}


	public static final int BUTTON_WIDTH = 28;

	public static final int BUTTON_HEIGHT = 28;

	public static final int BUTTON_PAD = 0;

	public static final int BUTTON_MARGIN = 4;

	private SongObserver songObserver;

	private java.util.List<JButton> buttons = new ArrayList<JButton>();

	private JButton toStartButton = new JButton();

	private JButton frevButton = new JButton();

	private JButton backButton = new JButton();

	private JButton stopButton = new JButton();

	private JButton playButton = new JButton();

	private JButton ffwdButton = new JButton();

	private JButton toEndButton = new JButton();

	private TimeControl timeControl = new TimeControl(this);

	private TimeRuler timeRuler = new TimeRuler(this);

	private JButton selected;


	public PlaybackControls(SongObserver songObserver) {
		setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
		this.songObserver = songObserver;

		add(timeControl);
		add(timeRuler);

		add(toStartButton);
		add(frevButton);
		add(backButton);
		add(stopButton);
		add(playButton);
		add(ffwdButton);
		add(toEndButton);

		buttons.add(toStartButton);
		buttons.add(frevButton);
		buttons.add(backButton);
		buttons.add(stopButton);
		buttons.add(playButton);
		buttons.add(ffwdButton);
		buttons.add(toEndButton);

		toStartButton.setAction(new PlaybackControlsAction("to-start") {
			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.toStartAction();
			}
		});
		frevButton.setAction(new PlaybackControlsAction("frev") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.frevAction();
			}
		});
		backButton.setAction(new PlaybackControlsAction("back") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.backAction();
			}
		});
		stopButton.setAction(new PlaybackControlsAction("stop") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.stopAction();
			}
		});
		playButton.setAction(new PlaybackControlsAction("play") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.playAction();
			}
		});
		ffwdButton.setAction(new PlaybackControlsAction("ffwd") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.ffwdAction();
			}
		});
		toEndButton.setAction(new PlaybackControlsAction("to-end") {

			public void actionPerformed(ActionEvent e) {
				PlaybackControls.this.songObserver.toEndAction();
			}
		});

		setLayout(new Layout(this) {
			public Dimension preferredLayoutSize(Container parent) {
				int buttonCount = buttons.size();
				return new Dimension((buttonCount * BUTTON_WIDTH) + ((buttonCount - 1) * BUTTON_PAD) + (2 * BUTTON_MARGIN), BUTTON_HEIGHT + (2 * BUTTON_MARGIN));
			}


			public void layoutContainer(Container parent) {
				timeControl.setBounds(10, 10, getSize().width - 20, 15);
				timeRuler.setBounds(10, 25, getSize().width - 20, 25);

				int buttonCount = buttons.size();
				int dx = getSize().width / 2 - ((buttonCount * BUTTON_WIDTH) + ((buttonCount - 1) * BUTTON_PAD) + (2 * BUTTON_MARGIN)) / 2;
				int dy = getSize().height - (BUTTON_HEIGHT + 2 * BUTTON_MARGIN);

				for (JButton btn : buttons) {
					btn.setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
					btn.setLocation(dx, dy);
					dx += BUTTON_WIDTH + BUTTON_PAD;
				}
			}
		});
	}


	public void receive(Event event) {
		String channel = event.getChannel();

		if (selected != null) {
			selected.setSelected(false);
		}

		if (channel.equals(SongObserver.TIME)) {
			timeControl.updateTime();
		}
		else if (channel.equals(SongObserver.TO_START)) {
			toStartButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.FREV)) {
			frevButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.BACK)) {
			backButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.STOP)) {
			stopButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.PLAY)) {
			playButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.FFWD)) {
			ffwdButton.setSelected(true);
		}
		else if (channel.equals(SongObserver.TO_END)) {
			toEndButton.setSelected(true);
		}
	}


	public abstract static class PlaybackControlsAction extends AbstractAction {

		public PlaybackControlsAction(String iconName) {
			ImageIcon icon = Resources.getImageIcon("images", iconName + ".png");
			putValue(Action.SMALL_ICON, icon);
		}
	}

	public static class TimeControl extends JComponent {

		private PlaybackControls pc;


		public TimeControl(PlaybackControls pc) {
			setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
			this.pc = pc;

			MouseAdapter adapter = new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					Point p = e.getPoint();
					double dx = (double) (p.x - 2) / (double) (getWidth() - 4);
					TimeControl.this.pc.songObserver.setFractionalTime(dx);
				}


				public void mouseDragged(MouseEvent e) {
					Point p = e.getPoint();
					double dx = (double) (p.x - 2) / (double) (getWidth() - 4);
					TimeControl.this.pc.songObserver.setFractionalTime(dx);
				}
			};
			addMouseListener(adapter);
			addMouseMotionListener(adapter);
		}


		public void paint(Graphics g) {
			super.paint(g);
			drawTime(g);
		}


		public void updateTime() {
			drawTime(getGraphics());
		}


		public void drawTime(Graphics g) {
			double frac = pc.songObserver.getFractionalTime();
			int w1 = (int) (frac * (double) (getWidth() - 4));
			int w2 = (getWidth() - 4) - (w1 + 1);

			g.setColor(Color.GRAY);
			g.fillRect(2, 2, w1, getHeight() - 3);

			g.setColor(getBackground());
			g.fillRect(w1 + 3, 2, w2, getHeight() - 3);

			g.setColor(Color.BLACK);
			g.drawLine(w1 + 3, 2, w1 + 3, getHeight() - 2);
		}
	}

	public static class TimeRuler extends JComponent {

		private PlaybackControls pc;


		public TimeRuler(PlaybackControls pc) {
			this.pc = pc;
		}


		public void paint(Graphics g) {
			super.paint(g);
			drawTime(g);
		}


		public void updateTime() {
			drawTime(getGraphics());
		}


		public void drawTime(Graphics g) {
			double start = pc.songObserver.getStartTime();
			double end = pc.songObserver.getEndTime();
			double length = end - start;
			double frac = pc.songObserver.getFractionalTime();

			double cWidth = (getWidth() - 4);
			for (double i = 0; i <= 10; i++) {
				double dt = i / 10;
				double t = length * dt;
				double x = 2 + (cWidth * dt);
				String s = DOUBLE_FORMAT.format(t);
				FontMetrics fm = g.getFontMetrics();
				int sw = fm.stringWidth(s);
				int sx = (int) x - sw/2;
				if(i == 0) {
					sx = 2;
				}
				else if (i == 10) {
					sx = (int) cWidth - sw + 2;
				}

				g.setColor(Color.BLACK);
				g.drawLine((int) x, 0, (int) x, 5);
				g.drawString(s, sx, 18);
			}
		}
	}
}